/*
 * SonarQube PDF Report
 * Copyright (C) 2010-2017 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonarsource.plugins.example.pdf;

import com.lowagie.text.Font;
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonarsource.plugins.example.pdf.entity.Project;
import org.sonarsource.plugins.example.pdf.entity.Qprofile;
import org.sonarsource.plugins.example.pdf.entity.Rule;
import org.sonarsource.plugins.example.pdf.entity.Violation;
import org.sonarsource.plugins.example.pdf.entity.exception.ReportException;
import org.sonarsource.plugins.example.pdf.util.Credentials;

import java.awt.*;
import java.net.URL;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Workbook for Team PDF Reporter
 * 团队 PDF 报告程序的工作簿
 */
public class TeamWorkbookPDFReporter extends ExecutivePDFReporter {
    private static final Logger LOG = LoggerFactory.getLogger(TeamWorkbookPDFReporter.class);
    /**
     *
     */
    private static final long serialVersionUID = 4994742577755351762L;


    public TeamWorkbookPDFReporter(final Credentials credentials, final URL logo, final String projectKey, final String branch,
                                   final Properties configProperties, final Properties langProperties) {
        super(credentials, logo, projectKey, branch, configProperties, langProperties);
    }

    /**
     * @see org.sonarsource.plugins.example.pdf.ExecutivePDFReporter#printSpecificData(Project,
     * Chapter)
     */
    @Override
    protected void printSpecificData(Project project, Chapter chapter) throws ReportException {
        // 问题详情
        printMostViolatedRulesDetails(project, chapter);

        // 质量配置
        // printQprofilerules(project, chapter);
    }

    /**
     * Print Qprofilerules
     * 质量配置
     *
     * @param project current project
     * @param chapter current chapter
     */

    private void printQprofilerules(Project project, Chapter chapter) {
        if (project.getQprofile() != null && !project.getQprofile().isEmpty()) {
            Section section = chapter.addSection(
                    new Paragraph(getTextProperty(PDFResources.GENERAL_QPROFILES), Style.TITLE_FONT));

            for (Qprofile qprofile : project.getQprofile()) {
                Section subSection = section.addSection(new Paragraph(qprofile.getLanguage(), Style.TITLE_FONT));
                subSection.add(createQprofilesTable(qprofile));
            }
        }
    }

    private PdfPTable createQprofilesTable(Qprofile qprofile) {
        List<org.sonarsource.plugins.example.ws.model.Rule> qprofilerules = qprofile.getQprofileRules();
        PdfPTable table = new PdfPTable(10);

        table.getDefaultCell().setColspan(2);
        table.getDefaultCell().setBackgroundColor(new Color(255, 228, 181));
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_QPROFILES), Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(8);
        table.getDefaultCell().setBackgroundColor(Color.WHITE);
        String typecount = getTypeCount(qprofilerules);
        table.addCell(new Phrase(qprofile.getLanguage() + ":" + qprofile.getName() + typecount, Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(10);
        table.getDefaultCell().setBackgroundColor(Color.GRAY);
        table.addCell("");

        table.getDefaultCell().setBackgroundColor(new Color(255, 228, 181));
        table.getDefaultCell().setColspan(6);
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_RULE), Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(2);
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_VIOLATIONS_TYPE), Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(2);
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_VIOLATIONS_SERVERITY), Style.NORMAL_FONT));

        table.getDefaultCell().setBackgroundColor(Color.WHITE);
        if (!qprofilerules.isEmpty()) {
            Map<String, Map<String, List<org.sonarsource.plugins.example.ws.model.Rule>>> groupByPriceMap1 =
                    qprofilerules.stream().collect(Collectors.groupingBy(org.sonarsource.plugins.example.ws.model.Rule::getType, Collectors.groupingBy(org.sonarsource.plugins.example.ws.model.Rule::getSeverity)));
            for (Map.Entry<String, Map<String, List<org.sonarsource.plugins.example.ws.model.Rule>>> entrys : groupByPriceMap1.entrySet()) {
                if (entrys.getKey().equals("BUG")) {
                    String type = getTextProperty(PDFResources.GENERAL_BUGS);
                    createTableByType(table, entrys, type);
                }
                if (entrys.getKey().equals("VULNERABILITY")) {
                    String type = getTextProperty(PDFResources.GENERAL_SECURITY);
                    createTableByType(table, entrys, type);
                }
                if (entrys.getKey().equals("CODE_SMELL")) {
                    String type = getTextProperty(PDFResources.GENERAL_MAINTAINABILITY);
                    createTableByType(table, entrys, type);
                }

            }
        } else {
            table.getDefaultCell().setColspan(10);
            PdfPCell cell = new PdfPCell(new Phrase("暂无数据", new Font()));
            // 单元格的水平垂直居中设置
            cell.setUseDescender(true);
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
            table.addCell(cell);
        }


        table.setSpacingBefore(20);
        table.setSpacingAfter(20);
        table.setLockedWidth(false);
        table.setWidthPercentage(90);
        return table;

    }

    private void createTableByType(PdfPTable table,
                                   Map.Entry<String, Map<String, List<org.sonarsource.plugins.example.ws.model.Rule>>> entrys, String type) {
        for (Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry : entrys.getValue().entrySet()) {
            if (entry.getKey().equals("BLOCKER")) {
                String serverity = getTextProperty(PDFResources.GENERAL_BLOCKER_VIOLATIONS);
                createTableByServerity(table, type, entry, serverity);
            }
        }
        for (Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry : entrys.getValue().entrySet()) {
            if (entry.getKey().equals("CRITICAL")) {
                String serverity = getTextProperty(PDFResources.GENERAL_CRITICAL_VIOLATIONS);
                createTableByServerity(table, type, entry, serverity);
            }
        }
        for (Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry : entrys.getValue().entrySet()) {
            if (entry.getKey().equals("MAJOR")) {
                String serverity = getTextProperty(PDFResources.GENERAL_MAJOR_VIOLATIONS);
                createTableByServerity(table, type, entry, serverity);
            }
        }
        for (Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry : entrys.getValue().entrySet()) {
            if (entry.getKey().equals("MINOR")) {
                String serverity = getTextProperty(PDFResources.GENERAL_MINOR_VIOLATIONS);
                createTableByServerity(table, type, entry, serverity);
            }
        }
        for (Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry : entrys.getValue().entrySet()) {
            if (entry.getKey().equals("INFO")) {
                String serverity = getTextProperty(PDFResources.GENERAL_INFO_VIOLATIONS);
                createTableByServerity(table, type, entry, serverity);
            }
        }
    }

    private void createTableByServerity(PdfPTable table, String type,
                                        Map.Entry<String, List<org.sonarsource.plugins.example.ws.model.Rule>> entry, String serverity) {
        for (org.sonarsource.plugins.example.ws.model.Rule rule : entry.getValue()) {
            table.getDefaultCell().setColspan(6);
            table.addCell(new Phrase(rule.getName(), Style.NORMAL_FONT));
            table.getDefaultCell().setColspan(2);
            table.addCell(new Phrase(type, Style.NORMAL_FONT));
            table.getDefaultCell().setColspan(2);
            table.addCell(new Phrase(serverity, Style.NORMAL_FONT));
        }
    }

    private String getTypeCount(List<org.sonarsource.plugins.example.ws.model.Rule> qprofilerules) {
        StringBuilder typecount = new StringBuilder();
        if (!qprofilerules.isEmpty()) {
            Map<String, Long> groupByPriceMaps =
                    qprofilerules.stream().collect(Collectors.groupingBy(org.sonarsource.plugins.example.ws.model.Rule::getType, Collectors.counting()));
            for (Map.Entry<String, Long> entry : groupByPriceMaps.entrySet()) {
                if (entry.getKey().equals("BUG")) {
                    typecount.append("   " + getTextProperty(PDFResources.GENERAL_BUGS) + ":" + entry.getValue());
                }
                if (entry.getKey().equals("VULNERABILITY")) {
                    typecount.append("   " + getTextProperty(PDFResources.GENERAL_SECURITY) + ":" + entry.getValue());
                }
                if (entry.getKey().equals("CODE_SMELL")) {
                    typecount.append("   " + getTextProperty(PDFResources.GENERAL_MAINTAINABILITY) + ":" + entry.getValue());
                }

            }
        }
        return typecount.toString();
    }

    /**
     * Print details for most violated rules
     * 问题详情
     *
     * @param project current project
     * @param chapter current chapter
     */
    private void printMostViolatedRulesDetails(final Project project, final Chapter chapter) {
        if (project.getMostViolatedRules() != null && !project.getMostViolatedRules().isEmpty()) {
            Section section = chapter.addSection(
                    new Paragraph(getTextProperty(PDFResources.GENERAL_VIOLATIONS_DETAILS), Style.TITLE_FONT));
            for (Rule rule : project.getMostViolatedRules()) {
                List<String> files = new LinkedList<>();
                List<String> lines = new LinkedList<>();
                addViolation(rule, files, lines);
                section.addSection(new Paragraph(rule.getName(), Style.TITLE_FONT))
                        .add(createViolationsDetailedTable(rule.getName(), rule.getDescription(), files, lines));
            }
        }
    }

    /**
     * Add violation
     * 添加违规
     *
     * @param rule  rule
     * @param files files
     * @param files files
     */
    private void addViolation(Rule rule, List<String> files, List<String> lines) {
        if (rule.getTopViolations() != null) {
            for (Violation violation : rule.getTopViolations()) {
                // 获取文件名 webflux-demo:src/main/java/com/example/webfluxdemo/MingYueUserController.java ==》 MingYueUserController.java
                String[] components = violation.getResource().split("/");
                files.add(components[components.length - 1]);
                if (Objects.isNull(violation.getLine()) || "N/A".equalsIgnoreCase(violation.getLine())) {
                    lines.add("0");
                } else {
                    lines.add(violation.getLine());
                }
            }
        }
    }

    /**
     * Create table for violation details
     * 为违规详细信息创建表
     *
     * @param ruleName name of the rules
     * @param files    violated files
     * @param lines    violated lines
     * @return The table (iText table) ready to add to the document
     */
    private PdfPTable createViolationsDetailedTable(final String ruleName, final String ruleDesc, final List<String> files,
                                                    final List<String> lines) {

        PdfPTable table = new PdfPTable(10);
        table.getDefaultCell().setColspan(1);
        table.getDefaultCell().setBackgroundColor(new Color(255, 228, 181));
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_RULE), Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(9);
        table.getDefaultCell().setBackgroundColor(Color.WHITE);
        table.addCell(new Phrase(ruleName, Style.NORMAL_FONT));

        // 规则描述
//        table.getDefaultCell().setColspan(2);
//        table.getDefaultCell().setBackgroundColor(new Color(255, 228, 181));
//        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_RULE_DESC), Style.NORMAL_FONT));
//
//        table.getDefaultCell().setColspan(8);
//        table.getDefaultCell().setBackgroundColor(Color.WHITE);
//        String html = convertHtml(ruleDesc);
//        table.addCell(new Phrase(html, Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(10);
        table.getDefaultCell().setBackgroundColor(Color.GRAY);
        table.addCell("");

        // 类信息集合
        table.getDefaultCell().setColspan(7);
        table.getDefaultCell().setBackgroundColor(new Color(255, 228, 181));
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_FILE), Style.NORMAL_FONT));

        table.getDefaultCell().setColspan(3);
        table.addCell(new Phrase(getTextProperty(PDFResources.GENERAL_LINE), Style.NORMAL_FONT));
        table.getDefaultCell().setBackgroundColor(Color.WHITE);

        int i = 0;
        String lineNumbers = "";
        if (!files.isEmpty()) {
            while (i < files.size() - 1) {
                if (("").equals(lineNumbers)) {
                    lineNumbers += lines.get(i);
                } else {
                    lineNumbers += ", " + lines.get(i);
                }

                if (!files.get(i).equals(files.get(i + 1))) {
                    table.getDefaultCell().setColspan(7);
                    table.addCell(files.get(i));
                    table.getDefaultCell().setColspan(3);
                    table.addCell(lineNumbers);
                    lineNumbers = "";
                }
                i++;
            }
        }

        if (!files.isEmpty()) {
            table.getDefaultCell().setColspan(7);
            table.addCell(files.get(files.size() - 1));
            table.getDefaultCell().setColspan(3);
            if (("").equals(lineNumbers)) {
                lineNumbers += lines.get(i);
            } else {
                lineNumbers += ", " + lines.get(lines.size() - 1);
            }
            table.addCell(lineNumbers);
        }

        table.setSpacingBefore(20);
        table.setSpacingAfter(20);
        table.setLockedWidth(false);
        table.setWidthPercentage(90);
        return table;
    }

    private String convertHtml(final String ruleDesc) {
        String html = ruleDesc.replaceAll("<.*?>", " ").replaceAll("", "");
        html = html.replaceAll("<.*?", "");
        html = html.replaceAll("&lt;", "<");
        html = html.replaceAll("&gt;", ">");
        html = html.replaceAll("&rsquo;", "’");
        html = html.replaceAll("&mdash;", "—");
        html = html.replaceAll("&ndash;", "–");
        return html;

    }

    /**
     * @see org.sonarsource.plugins.example.pdf.ExecutivePDFReporter#getReportType()
     */
    @Override
    public String getReportType() {
        return PDFResources.WORKBOOK_REPORT_TYPE;
    }
}